package fetch;

import com.mongodb.DBObject;
import db.mongo.MongoDao;
import org.apache.http.*;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.*;
import java.util.*;

/**
 * @fileName: Fetcher
 * @author: Han
 * @date: 2018/5/29 13:12
 * @dscription: TODO
 */
public class Fetcher {

    /**
     * 返回代理服务器地址
     *
     * @return 地址
     */
    private SocketAddress getSocketAddressProxy() {
        SocketAddress socketAddress = null;
        Object[] proxyArr = getProxyIpPort();
        String ip = (String) proxyArr[0];
        int port = (Integer) proxyArr[1];
        if (!Objects.isNull(ip) && !Objects.isNull(port)) {
            socketAddress = new InetSocketAddress(ip, port);
        }
        return socketAddress;
    }

    public HttpHost getHttpHostProxy(){

        HttpHost httpHost = null;
        Object[] proxyArr = getProxyIpPort();
        String ip = (String) proxyArr[0];
        int port = (Integer) proxyArr[1];
        if (!Objects.isNull(ip) && !Objects.isNull(port)) {
            httpHost = new HttpHost(ip, port);
        }
        return httpHost;
    }

    /**
     * 从指定库中取出代理ip和端口
     *
     * @return 代理对象
     */
    private Object[] getProxyIpPort() {

        Object[] proxy = new Object[2];

        Random random = new Random();
        //获取HttpHost,如果获取失败,重复指定次数,超过则退出程序
        int maxRepeatCount = 4;
        int repeatCount = 0;
        while (repeatCount++ <= maxRepeatCount) {
            try {
                //随机查找记录
                int flagInt = random.nextInt(6) + 1;
                String[] keys = {"flag"};
                Object[] values = {flagInt};
                DBObject dbObject = MongoDao.getMongoDaoInstance().find("siteHost", "proxy", 1, keys, values).get(0);
                proxy[0] = dbObject.get("ip");
                proxy[1] = dbObject.get("port");
                break;
            } catch (Exception e) {
                if (repeatCount <= maxRepeatCount) {
                    //如果失败,等待10秒重试
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException ee) {
                        ee.printStackTrace();
                    }
                    System.err.println("获取代理ip失败,重试第" + repeatCount + "次");
                    e.printStackTrace();
                } else {
                    System.err.println("获取代理ip超时,程序结束");
                    e.printStackTrace();
                }
            }
        }

        return proxy;
    }

    /**
     * 通过post方式获取HttPResponse
     *
     * @param urlStr            url
     * @param headers           请求头
     * @param nameValuePairList 表单数据
     * @param proxy             代理
     * @return 对象
     * @throws Exception 抛出异常
     */
    private HttpResponse getResponseByPost(String urlStr, Header[] headers, List<NameValuePair> nameValuePairList,
                                           HttpHost proxy) throws Exception {
        HttpResponse response;
        //建立HttpClient对象
        HttpClient httpClient = HttpClients.createDefault();
        //建立POST请求
        HttpPost post = null;
        try {
            post = new HttpPost(urlStr);
            //配置代理
            RequestConfig config = RequestConfig.custom().setProxy(proxy).build();
            post.setConfig(config);
            post.setHeaders(headers);
            HttpEntity formData = new UrlEncodedFormEntity(nameValuePairList, Consts.UTF_8);
            post.setEntity(formData);
            //发送POST请求
            response = httpClient.execute(post);
        } catch (Exception e) {
            //出现异常,先关闭连接再抛出
            Objects.requireNonNull(post).abort();
            throw e;
        } finally {
            Objects.requireNonNull(post).abort();
        }

        return response;
    }

    /**
     * 使用get方式获取response
     *
     * @param urlStr  目标url
     * @param headers 请求头
     * @param proxy   代理
     * @return response
     * @throws Exception 抛出异常
     */
    public String getPageContentByGet(String urlStr, Header[] headers, HttpHost proxy) throws Exception {
        String pageContent;
        HttpClient httpClient = HttpClients.createDefault();
        HttpGet get = null;
        try {
            get = new HttpGet(urlStr);
            if (!Objects.isNull(proxy)) {
                //配置代理
                RequestConfig config = RequestConfig.custom().setProxy(proxy).build();
                get.setConfig(config);
            }
            get.setHeaders(headers);
            HttpResponse response = httpClient.execute(get);
            HttpEntity entity = response.getEntity();
            // 获取字节数组
            byte[] content = EntityUtils.toByteArray(entity);
            pageContent = new String(content, "utf-8");
        } catch (Exception e) {
            //出现异常,先关闭连接再抛出
            Objects.requireNonNull(get).abort();
            throw e;
        } finally {
            Objects.requireNonNull(get).abort();
        }

        return pageContent;
    }

    /**
     * 使用HttpURLConnection通过get方式获取数据
     * @param urlStr 目的地址
     * @param headers 请求头
     * @param addr 代理地址
     * @throws Exception 抛出异常
     */
    private void getResponseByGet(String urlStr, Map<String, String> headers, SocketAddress addr) throws Exception {

        HttpURLConnection httpURLConnection = (HttpURLConnection) new URL(urlStr).openConnection(
                new Proxy(Proxy.Type.HTTP, addr));
        //设置请求方式为GET
        httpURLConnection.setRequestMethod("GET");
        //不重定向
        httpURLConnection.setInstanceFollowRedirects(true);
        //设置请求头
        Set<String> keySet = headers.keySet();
        for (String key : keySet) {
            String value = headers.get(key);
            httpURLConnection.setRequestProperty(key, value);
        }
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream(),
                "utf8"))) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        }
    }
}
